package org.eiahe.hr.attendance.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.ehe.system.service.IHrEmployeeService;
import org.eiahe.hr.attendance.domain.LeaveApplication;
import org.eiahe.hr.attendance.domain.OvertimeRecord;
import org.eiahe.hr.attendance.domain.bo.LeaveApplicationBo;
import org.eiahe.hr.attendance.domain.vo.LeaveApplicationVo;
import org.eiahe.hr.attendance.event.LeaveApprovalEvent;
import org.eiahe.hr.attendance.mapper.LeaveApplicationMapper;
import org.eiahe.hr.attendance.service.ILeaveApplicationService;
import org.eiahe.hr.attendance.service.IAttendanceAlgorithmService;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.system.domain.HrEmployee;
import org.ehe.system.mapper.HrEmployeeMapper;
import org.eiahe.hr.filler.EmployeeNameFiller;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 请假申请Service业务层处理
 *
 * @author zhangnn
 */
@RequiredArgsConstructor
@Service
public class LeaveApplicationServiceImpl implements ILeaveApplicationService {

    private final LeaveApplicationMapper baseMapper;
    private final IHrEmployeeService employeeService;
    private final Converter converter;
    private final IAttendanceAlgorithmService attendanceAlgorithmService;
    private final ApplicationEventPublisher eventPublisher;
    private final EmployeeNameFiller employeeNameFiller;

    /**
     * 请假类型映射
     */
    private static final Map<String, String> LEAVE_TYPE_MAP = new HashMap<>();

    static {
        LEAVE_TYPE_MAP.put("1", "事假");
        LEAVE_TYPE_MAP.put("2", "病假");
        LEAVE_TYPE_MAP.put("3", "年假");
        LEAVE_TYPE_MAP.put("4", "调休");
        LEAVE_TYPE_MAP.put("5", "婚假");
        LEAVE_TYPE_MAP.put("6", "产假");
        LEAVE_TYPE_MAP.put("7", "陪产假");
        LEAVE_TYPE_MAP.put("8", "丧假");
    }

    /**
     * 查询请假申请
     */
    @Override
    public LeaveApplicationVo queryById(Long applicationId) {
        LeaveApplicationVo vo = baseMapper.selectVoById(applicationId);
        if (vo != null) {
            employeeNameFiller.fillEmployeeName(vo,LeaveApplicationVo::getEmployeeNo,LeaveApplicationVo::setEmployeeName);
            vo.setLeaveTypeName(LEAVE_TYPE_MAP.get(vo.getLeaveType()));
        }
        return vo;
    }

    /**
     * 查询请假申请列表
     */
    @Override
    public TableDataInfo<LeaveApplicationVo> queryPageList(LeaveApplicationBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<LeaveApplication> lqw = buildQueryWrapper(bo);
        Page<LeaveApplicationVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);

        // 填充员工姓名和请假类型名称
        result.getRecords().forEach(vo -> {
            employeeNameFiller.fillEmployeeName(vo,LeaveApplicationVo::getEmployeeNo,LeaveApplicationVo::setEmployeeName);
            vo.setLeaveTypeName(LEAVE_TYPE_MAP.get(vo.getLeaveType()));
        });

        return TableDataInfo.build(result);
    }

    /**
     * 查询请假申请列表
     */
    @Override
    public List<LeaveApplicationVo> queryList(LeaveApplicationBo bo) {
        LambdaQueryWrapper<LeaveApplication> lqw = buildQueryWrapper(bo);
        List<LeaveApplicationVo> list = baseMapper.selectVoList(lqw);

        // 填充员工姓名和请假类型名称
        list.forEach(vo -> {
            employeeNameFiller.fillEmployeeName(vo,LeaveApplicationVo::getEmployeeNo,LeaveApplicationVo::setEmployeeName);
            vo.setLeaveTypeName(LEAVE_TYPE_MAP.get(vo.getLeaveType()));
        });

        return list;
    }

    private LambdaQueryWrapper<LeaveApplication> buildQueryWrapper(LeaveApplicationBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<LeaveApplication> lqw = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(bo.getEmployeeName())) {
            List<String> employeeNos = employeeService.queryByEmployeeName(bo.getEmployeeName());
            if (CollUtil.isEmpty(employeeNos)) {
                lqw.eq(LeaveApplication::getEmployeeNo, -1);
            } else {
                lqw.in(LeaveApplication::getEmployeeNo, employeeNos);
            }
        }
        //lqw.eq(StringUtils.isNotBlank(bo.getEmployeeNo()), LeaveApplication::getEmployeeNo, bo.getEmployeeNo());
        lqw.eq(bo.getUserId() != null, LeaveApplication::getUserId, bo.getUserId());
        lqw.eq(StringUtils.isNotBlank(bo.getLeaveType()), LeaveApplication::getLeaveType, bo.getLeaveType());
        lqw.eq(StringUtils.isNotBlank(bo.getApprovalStatus()), LeaveApplication::getApprovalStatus,
                bo.getApprovalStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getSource()), LeaveApplication::getSource, bo.getSource());
        lqw.eq(StringUtils.isNotBlank(bo.getOaId()), LeaveApplication::getOaId, bo.getOaId());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), LeaveApplication::getStatus, bo.getStatus());

        // 日期范围查询
        if (params.get("beginStartTime") != null && params.get("endStartTime") != null) {
            lqw.between(LeaveApplication::getStartTime,
                    params.get("beginStartTime"), params.get("endStartTime"));
        }

        lqw.orderByDesc(LeaveApplication::getCreateTime);
        return lqw;
    }

    /**
     * 新增请假申请
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(LeaveApplicationBo bo) {
        // 校验时间合法性
        validateLeaveTime(bo);

        LeaveApplication add = converter.convert(bo, LeaveApplication.class);
        // 如果未设置来源,默认为本地录入
        if (StringUtils.isBlank(add.getSource())) {
            add.setSource("LOCAL");
        }

        // 自动计算请假天数(扣除午休、非工作日)
        if (add.getLeaveDays() == null && add.getStartTime() != null && add.getEndTime() != null) {
            add.setLeaveDays(attendanceAlgorithmService.calculateLeaveDays(
                    add.getEmployeeNo(), add.getStartTime(), add.getEndTime()));
        }

        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setApplicationId(add.getApplicationId());
        }
        return flag;
    }

    /**
     * 修改请假申请
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(LeaveApplicationBo bo) {
        // 校验时间合法性
        validateLeaveTime(bo);

        LeaveApplication update = converter.convert(bo, LeaveApplication.class);

        // 自动重新计算请假天数
        if (update.getStartTime() != null && update.getEndTime() != null) {
            update.setLeaveDays(attendanceAlgorithmService.calculateLeaveDays(
                    update.getEmployeeNo(), update.getStartTime(), update.getEndTime()));
        }

        return baseMapper.updateById(update) > 0;
    }

    /**
     * 校验请假时间合法性
     */
    private void validateLeaveTime(LeaveApplicationBo bo) {
        if (bo.getStartTime() != null && bo.getEndTime() != null) {
            if (bo.getStartTime().isAfter(bo.getEndTime())) {
                throw new RuntimeException("开始时间不能晚于结束时间");
            }
        }
    }

    /**
     * 校验并批量删除请假申请信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids) {
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 审批通过
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean approve(Long applicationId) {
        // 查询请假申请
        LeaveApplication application = baseMapper.selectById(applicationId);
        if (application == null) {
            throw new RuntimeException("请假申请不存在");
        }

        // 检查当前状态
        if ("3".equals(application.getApprovalStatus())) {
            throw new RuntimeException("该申请已经审批通过");
        }
        if ("4".equals(application.getApprovalStatus())) {
            throw new RuntimeException("该申请已被拒绝");
        }

        // 更新审批状态
        application.setApprovalStatus("3"); // 已通过
        boolean success = baseMapper.updateById(application) > 0;

        if (success) {
            // 发布请假审批事件
            LeaveApprovalEvent event = new LeaveApprovalEvent(
                    this,
                    application.getApplicationId(),
                    application.getEmployeeNo(),
                    application.getUserId(),
                    application.getStartTime(),
                    application.getEndTime(),
                    application.getLeaveType(),
                    application.getApprovalStatus());
            eventPublisher.publishEvent(event);
        }

        return success;
    }

    /**
     * 审批拒绝
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean reject(Long applicationId, String rejectReason) {
        // 查询请假申请
        LeaveApplication application = baseMapper.selectById(applicationId);
        if (application == null) {
            throw new RuntimeException("请假申请不存在");
        }

        // 检查当前状态
        if ("3".equals(application.getApprovalStatus())) {
            throw new RuntimeException("该申请已经审批通过,无法拒绝");
        }
        if ("4".equals(application.getApprovalStatus())) {
            throw new RuntimeException("该申请已被拒绝");
        }

        // 更新审批状态
        application.setApprovalStatus("4"); // 已拒绝
        application.setRemark(rejectReason);
        return baseMapper.updateById(application) > 0;
    }
}
